package com.dreamycode.paths;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Properties;

/**
 * Represents only a file NOT a folder.
 * Provides all the handy methods of java.io.File and relates to the
 * Folder interface.
 *
 * @see Path
 * @see Folder
 * @see Paths
 *
 * @author Eli Doran <eli@elidoran.com>
 *
 * @since 1.0
 */
public interface File extends Path
{

    /**
     * Loads the file into a {@link Properties} object.
     *
     * @since 1.0
     */
    Properties asProperties() throws IOException;

    /**
     * Loads the file into the specified {@link Properties} object.
     *
     * @since 1.0
     */
    Properties asProperties(Properties props) throws IOException;

    /**
     * Creates a lock on the file. This does not allow creating an output stream that will append
     * to the file. If you want to append to the file once locked then use {@link #lock(boolean)}
     * instead.
     *
     * @return true if it succeeded in getting the lock, false otherwise.
     *
     * @since 1.0
     */
    boolean lock();

    /**
     * Creates a lock on the file. This may allow creating an output stream that will append
     * to the file if the boolean is true. If you don't want to append to the file once locked then you may use {@link #lock()}
     * instead.
     *
     * @param append If true then appending output streams are possible after lock, else they are not.
     *
     * @return true if it succeeded in getting the lock, false otherwise.
     *
     * @since 1.0
     */
    boolean lock(boolean append);

    /**
     * Removes the lock on the file.
     *
     * @return true if the lock was released.
     *
     * @since 1.0
     */
    boolean unlock();

    /**
     * Returns true if this file is maintaining a lock on the file.
     *
     * @return true if this is maintaining a lock on the file.
     *
     * @since 1.0
     */
    boolean isLocked();

    /**
     * Returns the {@link FileLock} for the file or null if there is no lock.
     *
     * @return the FileLock if there is one.
     *
     * @since 1.0
     */
    FileLock getLock();

    /**
     * Returns true if the file is readable.
     *
     * @return true if the file is readable
     *
     * @since 1.0
     */
    boolean isReadable();

    /**
     * Returns true if the file is writable.
     *
     * @return true if the file is writable
     *
     * @since 1.0
     */
    boolean isWritable();

    /**
     * Returns the number of bytes contained in the file.
     *
     * @return the length of the file's contents.
     *
     * @since 1.0
     */
    long getLength();

    /**
     * Returns the file's extension or the empty string if it doesn't have one.
     *
     * The extension is every char after the last period.
     */
    String getExtension();

    /**
     * Returns whether it succeeded to make the file read-only.
     *
     * @return whether it succeeded.
     *
     * @since 1.0
     */
    boolean setReadOnly();


    /**
     * Returns a FileInputStream for this file.
     *
     * @return a FileInputStream for this file.
     *
     * @since 1.0
     */
    FileInputStream getInputStream() throws IOException;

    /**
     * Returns a BufferedInputStream for this file.
     *
     * @return a BufferedInputStream for this file.
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedInputStream getBufferedInputStream() throws IOException;

    /**
     * Returns a BufferedInputStream for this file.
     *
     * @return a BufferedInputStream for this file.
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedInputStream getBufferedInputStream(int size) throws IOException;


    /**
     * Returns a FileReader for this file.
     *
     * @return FileReader
     *
     * @since 1.0
     */
    FileReader getReader() throws IOException;

    /**
     * Returns a BufferedReader wrapping the FileReader for this file.
     *
     * @return BufferedReader
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedReader getBufferedReader() throws IOException;

    /**
     * Returns a BufferedReader wrapping the FileReader for this file.
     *
     * @return BufferedReader
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedReader getBufferedReader(int size) throws IOException;


    /**
     * Returns a FileOutputStream for this file.
     * This clears the file instead of appending. If you want to append to the
     * file's contents use {@link #getOutputStream(boolean)} and pass true.
     *
     * @return FileOutputStream
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileOutputStream getOutputStream() throws IOException;

    /**
     * Returns a FileOutputStream for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file you could use {@link #getOutputStream()}.
     *
     * @param append True if the file is to be appended to.
     *
     * @return FileOutputStream
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileOutputStream getOutputStream(boolean append) throws IOException;

    /**
     * Returns a BufferedOutputStream for this file.
     * This clears the file instead of appending. If you want to append to the
     * file's contents use {@link #getBufferedOutputStream(boolean)} and pass true.
     *
     * @return BufferedOutputStream
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedOutputStream getBufferedOutputStream() throws IOException;

    /**
     * Returns a BufferedOutputStream for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing.
     * If you want to write anew to the file then use {@link #getOutputStream()}.
     *
     * @param append True if the file is to be appended to.
     *
     * @return FileOutputStream
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedOutputStream getBufferedOutputStream(boolean append) throws IOException;

    /**
     * Returns a BufferedOutputStream for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing.
     * If you want to write anew to the file then use {@link #getOutputStream()}.
     *
     * @param size The size of the buffer.
     *
     * @return FileOutputStream
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedOutputStream getBufferedOutputStream(int size) throws IOException;

    /**
     * Returns a BufferedOutputStream for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing.
     * If you want to write anew to the file then use {@link #getOutputStream()}.
     *
     * @param size The size of the buffer.
     * @param append True if the file is to be appended to.
     *
     * @return FileOutputStream
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedOutputStream getBufferedOutputStream(int size, boolean append) throws IOException;


    /**
     * Returns a FileWriter for this file.
     * This clears the file instead of appending. If you want to append to the
     * file's contents use {@link #getWriter(boolean)} and pass true.
     *
     * @return FileWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileWriter getWriter() throws IOException;

    /**
     * Returns a FileWriter for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file you could use {@link #getWriter()}.
     *
     * @param append True if the file is to be appended to.
     *
     * @return FileWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileWriter getWriter(boolean append) throws IOException;

    /**
     * Returns a BufferedWriter wrapping the FileWriter for this file.
     * This clears the file instead of appending. If you want to append to the
     * file's contents use {@link #getBufferedWriter(boolean)} and pass true.
     *
     * @return BufferedWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedWriter getBufferedWriter() throws IOException;

    /**
     * Returns a BufferedWriter wrapping the FileWriter for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file then use {@link #getBufferedWriter()}.
     *
     * @param append True if the file is to be appended to.
     *
     * @return BufferedWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedWriter getBufferedWriter(boolean append) throws IOException;

    /**
     * Returns a BufferedWriter wrapping the FileWriter for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file then use {@link #getBufferedWriter()}.
     *
     * @param size The size of the buffer.
     *
     * @return BufferedWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedWriter getBufferedWriter(int size) throws IOException;

    /**
     * Returns a BufferedWriter wrapping the FileWriter for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file you could use {@link #getBufferedWriter()}.
     *
     * @param size The size of the buffer.
     * @param append True if the file is to be appended to.
     *
     * @return BufferedWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    BufferedWriter getBufferedWriter(int size, boolean append) throws IOException;

    /**
     * Returns a PrintWriter wrapping a BufferedWriter and the FileWriter
     * for this file.
     * This clears the file instead of appending. If you want to append to the
     * file's contents use {@link #getPrintWriter(boolean)} and pass true.
     *
     * @return PrintWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    PrintWriter getPrintWriter() throws IOException;

    /**
     * Returns a PrintWriter wrapping a BufferedWriter and the FileWriter
     * for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file you could use {@link #getPrintWriter()}.
     *
     * @param append True if the file is to be appended to.
     *
     * @return PrintWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    PrintWriter getPrintWriter(boolean append) throws IOException;

    /**
     * Returns a PrintWriter wrapping a BufferedWriter and the FileWriter
     * for this file.
     *
     * @param size The size of the buffer.
     *
     * @return PrintWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    PrintWriter getPrintWriter(int size) throws IOException;

    /**
     * Returns a PrintWriter wrapping a BufferedWriter and the FileWriter
     * for this file.
     * This may append to the file's contents, if 'append' is true, instead of clearing. If you want to
     * write anew to the file you could also use {@link #getPrintWriter()}.
     *
     * @param size The size of the buffer.
     * @param append True if the file is to be appended to.
     *
     * @return PrintWriter
     *
     * @throws IOException
     *
     * @since 1.0
     */
    PrintWriter getPrintWriter(int size, boolean append) throws IOException;

    /**
     * Returns the FileChannel for this file using a FileInputStream.
     *
     * @return FileChannel
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileChannel getInChannel() throws IOException;

    /**
     * Returns the FileChannel for this file using a FileOutputStream.
     *
     * @return FileChannel
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileChannel getOutChannel() throws IOException;

    /**
     * Returns the FileChannel for this file.
     *
     * @return FileChannel
     *
     * @throws IOException
     *
     * @since 1.0
     */
    FileChannel getOutChannel(boolean append) throws IOException;

}


/*
 * Copyright 2010 Eli Doran
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
